package com.example.oj.service.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.oj.entity.Question;
import com.example.oj.entity.Submit;
import com.example.oj.entity.SysOption;
import com.example.oj.entity.User;
import com.example.oj.mapper.SubmitMapper;
import com.example.oj.service.*;
import com.example.ojcommon.common.*;
import com.example.ojcommon.constant.CommonConstant;
import com.example.ojcommon.constant.UserConstant;
import com.example.ojcommon.enums.LanguageEnum;
import com.example.ojcommon.enums.SubmitStatusEnum;
import com.example.ojcommon.exception.BusinessException;
import com.example.oj.entity.dto.submit.SubmitAddRequest;
import com.example.oj.entity.dto.submit.SubmitQueryRequest;
import com.example.oj.entity.vo.QuestionVO;
import com.example.oj.entity.vo.SubmitVO;
import com.example.oj.entity.vo.UserVO;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author lenovo131
 * @description 针对表【submit(题目提交)】的数据库操作Service实现
 * @createDate 2023-10-26 09:30:28
 */
@Service
public class SubmitServiceImpl extends ServiceImpl<SubmitMapper, Submit>
    implements SubmitService {

  @Resource
  private QuestionService questionService;

  @Resource
  private UserService userService;

  @Resource
  private SubmitMapper submitMapper;

  @Resource
  private SysEnumsService sysEnumsService;

  @Resource
  private RabbitTemplate rabbitTemplate;

  @Override
  public void doSubmitQuestion(SubmitAddRequest submitAddRequest, HttpServletRequest request) {
    if (submitAddRequest == null) {
      throw new BusinessException(ErrorCode.PARAMS_ERROR, "提交请求失败");
    }
    //判断题目是否存在
    Long questionId = submitAddRequest.getQuestionId();
    Question question = questionService.getById(questionId);
    if (question == null) {
      throw new BusinessException(ErrorCode.NOT_FOUND_ERROR);
    }
    //判断语言是否存在
    Integer language = submitAddRequest.getLanguage();
    List<Map<String, Object>> languageList = sysEnumsService.getEnumsList("语言分类");
    boolean flag = false;
    for (Map<String, Object> obj : languageList) {
      if (obj.get("value").equals(language)) {
        flag = true;
        break;
      }
    }
    if (!flag) {
      throw new BusinessException(ErrorCode.PARAMS_ERROR, "不存在该语言");
    }
    // 根据用户id和题目id获取用户在最近一次提交,如果该提交还未执行结束,不允许继续提交
    User user = (User) request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
    Long userId = user.getId();
    Integer notFinish = submitMapper.getNotFinish(questionId, userId);
    if (notFinish != 0) {
      throw new BusinessException(ErrorCode.OPERATION_ERROR, "还有未完成的提交");
    }
    //在提交表插入数据
    Submit submit = new Submit();
    submit.setLanguage(language);
    submit.setCode(submitAddRequest.getCode());
    submit.setJudgeInfo("");
    submit.setStatus(1);
    submit.setQuestionId(questionId);
    submit.setUserId(userId);
    boolean save = this.save(submit);
    if (!save) {
      throw new BusinessException(ErrorCode.OPERATION_ERROR, "数据插入失败");
    }
    // 交给代码沙箱执行,发送给消息队列，由消费者处理
    ExecuteCodeRequest executeCodeRequest = new ExecuteCodeRequest();
    executeCodeRequest.setQuestionId(questionId);
    executeCodeRequest.setSubmitId(submit.getId());
    executeCodeRequest.setLanguage(submit.getLanguage());
    executeCodeRequest.setCode(submit.getCode());
    List<JudgeCase> list = JSONUtil.toList(question.getJudgeCase(), JudgeCase.class);
    List<String> collect = list.stream().map(JudgeCase::getInput).collect(Collectors.toList());
    executeCodeRequest.setInputList(collect);
    rabbitTemplate.convertAndSend("questionExchange", "question", executeCodeRequest);
//    rabbitTemplate.convertAndSend("questionExchange", "question", JSONUtil.toJsonStr(executeCodeRequest));
  }

  @Override
  public SubmitVO getSubmitVO(Submit submit) {
    if (submit == null) {
      return null;
    }
    SubmitVO submitVO = new SubmitVO();
    Long questionId = submit.getQuestionId();
    Long userId = submit.getUserId();
    String judgeInfo = submit.getJudgeInfo();
    //封装属性
    submitVO.setId(submit.getId());
    QuestionVO questionVO = questionService.getQuestionVOById(questionId);
    submitVO.setQuestion(questionVO);
    User user = userService.getById(userId);
    UserVO userVO = userService.getUserVO(user);
    submitVO.setUser(userVO);
    submitVO.setCode(submit.getCode());
    List<Map<String, Object>> languageList = sysEnumsService.getEnumsList("语言分类");
    for (Map<String, Object> obj : languageList) {
      if (obj.get("value").equals(submit.getLanguage())) {
        submitVO.setLanguageText(obj.get("text").toString());
        submitVO.setLanguage((Integer) obj.get("value"));
        break;
      }
    }
    if (judgeInfo != null && !judgeInfo.isEmpty()) {
      submitVO.setJudgeInfo(JSONUtil.toBean(judgeInfo, JudgeInfo.class));
    }
    SubmitStatusEnum submitStatusEnum = SubmitStatusEnum.valueOf(submit.getStatus());
    if (submitStatusEnum == null) {
      throw new BusinessException(ErrorCode.PARAMS_ERROR);
    }
    submitVO.setStatus(submitStatusEnum.getValue());
    submitVO.setStatusText(submitStatusEnum.getText());
    submitVO.setCreateTime(submit.getCreateTime());
    return submitVO;
  }

  @Override
  public Page<SubmitVO> getSubmitVOPage(Page<Submit> submitPage) {
    List<Submit> submitList = submitPage.getRecords();
    Page<SubmitVO> submitVOPage = new Page<>(submitPage.getCurrent(), submitPage.getSize(), submitPage.getTotal());
    if (CollectionUtils.isEmpty(submitList)) {
      return submitVOPage;
    }
    List<SubmitVO> submitVOList = submitList.stream().map(this::getSubmitVO).collect(Collectors.toList());
    submitVOPage.setRecords(submitVOList);
    return submitVOPage;
  }

  @Override
  public Page<SubmitVO> listPageQuestionVO(SubmitQueryRequest submitQueryRequest) {
    String title = submitQueryRequest.getTitle();
    Integer language = submitQueryRequest.getLanguage();
    String submitState = submitQueryRequest.getSubmitState();
    long current = submitQueryRequest.getCurrent();
    long pageSize = submitQueryRequest.getPageSize();
    String sortField = submitQueryRequest.getSortField();
    String sortOrder = submitQueryRequest.getSortOrder();

    QueryWrapper<Question> questionWrapper = new QueryWrapper<>();
    questionWrapper.like(ObjectUtils.isNotEmpty(title) && !title.isEmpty(), "title", title);
    List<Question> questionList = questionService.list(questionWrapper);
    if (ObjectUtils.isEmpty(questionList)) {
      return new Page<SubmitVO>(current, pageSize);
    }
    List<Long> ids = questionList.stream().map(Question::getId).collect(Collectors.toList());
    QueryWrapper<Submit> queryWrapper = new QueryWrapper<>();

    queryWrapper.eq(ObjectUtils.isNotEmpty(language), "language", language);
    queryWrapper.like(ObjectUtils.isNotEmpty(submitState), "judgeInfo", submitState);
    queryWrapper.in("questionId", ids);
    queryWrapper.orderBy(ObjectUtils.isNotEmpty(sortField), sortOrder.equals(CommonConstant.SORT_ORDER_ASC), sortField);
    Page<Submit> submitPage = submitMapper.selectPage(new Page<>(current, pageSize), queryWrapper);
    return this.getSubmitVOPage(submitPage);
  }

  @Override
  public void updateStateById(Long id) {
    submitMapper.updateStateById(id);
  }

}




